package de.saarland.uni.lego3d.server;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

import de.saarland.uni.lego3d.Lego3D;

/**
 * Thread class that takes care of incoming datagram messages. Incoming messages
 * are wrapped into the according datastructures and routed to the
 * InteractionHandler.
 */
public class ReceiverThread extends Thread {

	/**
	 * The server socket, given by the according paramter in the constructor
	 */
	private DatagramSocket serverSocket = null;

	/**
	 * Interaction handler to pass the wrapped interaction messages to
	 */
	private InteractionHandler handler;

	/**
	 * Flag that indicates whether the thread is still running
	 */
	private boolean running = true;

	/**
	 * Global separator for messages
	 */
	private final String seperator = "#";

	/**
	 * Creates a new receiver thread to receive message from the clients.
	 * 
	 * @param serverSocket
	 *            - the socket
	 * @param handler
	 *            - the interaction handler
	 */
	public ReceiverThread(DatagramSocket serverSocket,
			InteractionHandler handler) {
		this.handler = handler;
		this.serverSocket = serverSocket;
	}

	/**
	 * Run method of the receiver thread.
	 */
	public void run() {
		while (running) {
			try {
				System.out.println("Thread started");
				System.out
						.println("connection established...waiting for messages");

				byte[] receiveData;
				DatagramPacket receivePacket;

				while (running) {
					if (Lego3D.DEBUG)
						System.out.println("Thread READING");

					receiveData = new byte[1024];
					receivePacket = new DatagramPacket(receiveData,
							receiveData.length);
					serverSocket.receive(receivePacket);

					String receivedRAW = new String(receivePacket.getData());
					String received = receivedRAW.trim();

					if (Lego3D.DEBUG)
						System.out.println("message received: " + received);

					// parse String
					String[] data = received.split(seperator);
					for (int i = 0; i < data.length; i++) {
						data[i] = data[i].replace("\"", "");
					}

					if (data[0].equalsIgnoreCase("CONNECT")) {
						// connect message of the android application
						String IP = receivePacket.getAddress().getHostAddress();
						System.out.println("IP: " + IP);
						handler.handleConnectMessage(IP);

					} else if (data[0].equalsIgnoreCase("DISCONNECT")) {
						// dis-connect message of the android application
						String IP = receivePacket.getAddress().getHostAddress();
						System.out.println("IP: " + IP);

					} else if (data[0].equalsIgnoreCase("NEW-BRICK")) {
						// new brick message of the android application
						String IP = receivePacket.getAddress().getHostAddress();

						int lastIndex = data.length - 1;
						int[] layout = new int[lastIndex - 1];

						if (layout.length == 1) {
							layout[0] = Integer.parseInt(data[1]);
						} else {

							for (int i = 1; i < layout.length; i++) {
								layout[i - 1] = Integer.parseInt(data[i]);
							}
						}

						int color = Integer.parseInt(data[lastIndex]);

						handler.handleNewBrickMessage(IP, new Legobrick(layout,
								color));

					} else if (data[0].equalsIgnoreCase("KINECT-ACTION")) {
						// kinect messages received from the kinect client
						try {
							KinectAction newKinectAction = new KinectAction(
									Integer.parseInt(data[1]),
									Integer.parseInt(data[2]),
									Integer.parseInt(data[3]),
									Integer.parseInt(data[4]),
									Integer.parseInt(data[5]),
									Integer.parseInt(data[6]),
									Boolean.parseBoolean(data[7]),
									Boolean.parseBoolean(data[8]),
									Boolean.parseBoolean(data[9]),
									Boolean.parseBoolean(data[10]),
									Boolean.parseBoolean(data[11]));

							handler.handleKinectActionMessage(newKinectAction);

						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			} catch (IOException e) {
				System.out.println("Exception IO");
			}
		}
	}

	/**
	 * Stops the thread. No more message can be received.
	 * 
	 * @param stop
	 */
	public synchronized void stop(boolean stop) {
		running = stop;
	}
}
